package core.domain.query;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;

import org.apache.commons.lang3.Validate;
import org.apache.log4j.Logger;
import org.springframework.orm.jpa.JpaCallback;
import org.springframework.util.CollectionUtils;

import core.domain.IdEntity;
import core.domain.query.expgen.JpaSearchExpGenerator;
import core.domain.util.DomainUtils;

public class EntityJpaCallback<T extends IdEntity> implements
		JpaCallback<List<T>> {
	
	public static final Logger logger = Logger.getLogger(EntityJpaCallback.class);

	private JpaSearchExpGenerator<T> generator;

	public EntityJpaCallback(JpaSearchExpGenerator<T> generator) {
		super();
		this.generator = generator;
	}

	public List<T> doInJpa(EntityManager em) throws PersistenceException {
		Validate.notNull(em);
		Validate.notNull(generator);

		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<T> dataCriteriaQuery = cb.createQuery((Class<T>) DomainUtils
						.getSingleParameterClass(generator.getClass()));
		Predicate searchPredicate = generator.generate(cb, dataCriteriaQuery,
				em);
		dataCriteriaQuery.distinct(generator.getDistinctable());
		if (searchPredicate != null) {
			dataCriteriaQuery.where(searchPredicate);
		}
		if (!CollectionUtils.isEmpty(generator.getGroupBy(cb))) {
			dataCriteriaQuery.groupBy(generator.getGroupBy(cb));
		}
		if (!CollectionUtils.isEmpty(generator.getOrderBy(cb))) {
			dataCriteriaQuery.orderBy(generator.getOrderBy(cb));
		}
		TypedQuery<T> dataQuery = em.createQuery(dataCriteriaQuery);
		dataQuery.setMaxResults(10000000);
		dataQuery.setFirstResult(0);
		return (List<T>) dataQuery.getResultList();
	}
}
